package com.juzipi.demo.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

public class NIOServer {

    //服务端
    public static void main(String[] args) throws IOException {
        /**
         * NIO 结合上面的 MyClient 使用
         */


        //负责轮询是否有新的连接
        Selector serverSelector = Selector.open();
        //负责轮询处理连接中的数据
        Selector clientSelector = Selector.open();

        new Thread() {

            @Override
            public void run() {
                try {
                    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
                    serverSocketChannel.socket().bind(new InetSocketAddress(9898));
                    serverSocketChannel.configureBlocking(false);
                    //OP_ACCEPT 表示服务器监听到了客户连接，服务器可以接收这个连接了
                    serverSocketChannel.register(serverSelector, SelectionKey.OP_ACCEPT);
                    while (true) {
                        //监控是否有新的连接，1指的是阻塞的时间为 1ms
                        if (serverSelector.select(1) > 0) {
                            Set<SelectionKey> selectionKeys = serverSelector.selectedKeys();
                            Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
                            while (keyIterator.hasNext()) {
                                SelectionKey key = keyIterator.next();
                                if (key.isAcceptable()) {
                                    //每来一个新连接，不需要创建一个线程，而是直接注册到clientSelector
                                    try {
                                        SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();
                                        channel.configureBlocking(false);
                                        //OP_READ 表示通道中已经有了可读的数据，可以执行读操作了（通道目前有数据，可以进行读操作了）
                                        channel.register(clientSelector, SelectionKey.OP_READ);
                                    } finally {
                                        keyIterator.remove();
                                    }
                                }
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();


        new Thread("线程名字：") {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();

                try {
                    int i =0;
                    while (true) {
                        //批量轮询是否有哪些连接有数据可读取，这里的1指的是阻塞的时间为 1ms
                        if (clientSelector.select(1) > 0) {
                            Set<SelectionKey> selectionKeys = clientSelector.selectedKeys();
                            Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
                            while (keyIterator.hasNext()) {
                                SelectionKey key = keyIterator.next();
                                if (key.isReadable()) {
                                    try {
                                        SocketChannel clientChannel = (SocketChannel) key.channel();
                                        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                                        //读取数据以块为单位批量读取
                                        clientChannel.read(byteBuffer);
                                        byteBuffer.flip();
                                        System.out.println(name + " , " + Charset.defaultCharset().newDecoder().decode(byteBuffer).toString()+i);
                                    } finally {
                                        keyIterator.remove();
                                        key.interestOps(SelectionKey.OP_READ);
                                    }
                                }
                            }
                        }
                        i++;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }.start();


    }

}
